using System;
using System.Configuration;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

using Crainiate.Data.Persistence.Providers;
using Crainiate.Data.Persistence.Providers.SqlServer;
using Crainiate.Data.Persistence.Tools.Properties;

namespace Crainiate.Data.Persistence.Tools
{
    public partial class SqlDeploymentForm : WizardBaseForm
    {
        private SqlContext _context;
        private SqlDeployment _deployment;
        private Assembly _assembly;
        private string[] _names;

        public SqlDeploymentForm()
        {
            InitializeComponent();
            _deployment = new SqlDeployment();

            cboDeploymentType.Items.Add("Validate and deploy to database");
            cboDeploymentType.Items.Add("Validate only (no changes are made)");
           
            cboDeploymentMode.Items.Add("Changes will preserve existing data");
            cboDeploymentMode.Items.Add("Changes will remove existing data");

            _deployment.DeploymentType = DeploymentType.Deploy;
            _deployment.DeploymentMode = DeploymentMode.Update;

            cboDeploymentType.SelectedIndex = 0;
            cboDeploymentMode.SelectedIndex = 0;

            if (Settings.Default.SqlProviderLastDeploymentType == "Validate")
            {
                _deployment.DeploymentType = DeploymentType.Deploy;
                cboDeploymentType.SelectedIndex = 1;

            }
            if (Settings.Default.SqlProviderLastDeploymentMode == "Overwrite")
            {
                _deployment.DeploymentMode = DeploymentMode.Overwrite;
                cboDeploymentMode.SelectedIndex = 1;
            }

            cboPrefix.Text = Settings.Default.SqlProviderLastPrefix;
        }

        public string[] Databases
        {
            get
            {
                return _names;
            }
        }

        public SqlContext Context
        {
            get
            {
                return _context;
            }
            set
            {
                _context = value;
                _deployment.Context = value;

                //Attempt to load databases
                try
                {
                    _names = _deployment.GetDatabaseNames();
                    cboDatabase.Items.AddRange(_names);

                    //Set to the last database value
                    int index = cboDatabase.Items.IndexOf(Settings.Default.SqlProviderLastDatabase);
                    if (index > -1) cboDatabase.SelectedIndex = index;
                }
                catch
                {
                    MessageBox.Show("An error occurred getting the list of database names.", "Database error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    WizardResult = WizardResult.Previous;
                    this.Close();
                }
            }
        }

        public SqlDeployment Deployment
        {
            get
            {
                return _deployment;
            }
        }

        public Assembly Assembly
        {
            get
            {
                return _assembly;
            }
            set
            {
                _assembly = value;
                SetPrefixes(value);
            }
        }

        protected override void OnNextClick(object sender, EventArgs e)
        {
            Settings.Default.SqlProviderLastDeploymentType = (cboDeploymentType.SelectedIndex == 0) ? "Deploy" : "Validate";
            Settings.Default.SqlProviderLastDeploymentMode = (cboDeploymentMode.SelectedIndex == 0) ? "Update" : "Overwrite";
            Settings.Default.SqlProviderLastDatabase = cboDatabase.Text;
            Settings.Default.SqlProviderLastPrefix = cboPrefix.Text;

            if (cboDeploymentType.SelectedIndex == 1) _deployment.DeploymentType = DeploymentType.Validate;
            if (cboDeploymentMode.SelectedIndex == 1) _deployment.DeploymentMode = DeploymentMode.Overwrite;
            _context.Prefix = cboPrefix.Text;

            Settings.Default.Save();

            base.OnNextClick(sender, e);
        }

        //Loop through and get unique namespace items
        private void SetPrefixes(Assembly assembly)
        {
            List<string[]> arrays = new List<string[]>();
            Type[] types = null;

            types = assembly.GetTypes();

            //Get a unique list of all possible namespaces
            foreach (Type type in types)
            {
                if (Crainiate.Data.Persistence.Providers.Deployment.IsDeployable(type))
                {
                    List<string> names = new List<string>(type.FullName.Split(".".ToCharArray()));
                    if (names.Count > 1) names.RemoveAt(names.Count - 1);

                    string[] namesArray = names.ToArray();

                    if (!MatchArray(arrays, namesArray)) arrays.Add(namesArray);
                }
            }

            //Load combo
            foreach (string[] array in arrays)
            {
                string result = string.Empty;

                foreach (string item in array)
                {
                    if (result != string.Empty) result += ".";
                    result += item;
                }
                cboPrefix.Items.Add(result);
            }

            if (cboPrefix.Items.Count > 0) cboPrefix.SelectedIndex = 0;
        }

        private bool MatchArray(List<string[]> arrays, string[] names)
        {
            foreach (string[] array in arrays)
            {
                bool flag = (array.GetLength(0) == names.GetLength(0));

                //Check dimensions
                if (flag)
                {
                    for (int i = 0; i < array.GetLength(0); i++)
                    {
                        if (!array[i].Equals(names[i]))
                        {
                            flag = false;
                            break;
                        }
                    }
                }
                if (flag) return true;
            }

            return false;
        }
    }
}